#pragma once
#include "SMTBasics.h"
#include "SMTData.h"
#include <qobject.h>
#include <qmap.h>
#include <qmutex.h>
#include <qreadwritelock.h>
#include <qwidget.h>
class SMTSlotUnit;

class SMTEventMgrPrivate;

class __declspec(dllimport) SMTOperatorROIElementPrivate
{
public:
	SMTOperatorROIElementPrivate();
	SMTOperatorROIElementPrivate(const SMTOperatorROIElementPrivate &elem);
	~SMTOperatorROIElementPrivate();

	bool isMask();
	void setIsMask(bool bVal);

	bool isUseRef();
	void setUseRef(bool bVal);

	bool getShape(SMTShape* shape);
	bool setShape(SMTShape& shape);

	void setVariable(const SMTVariable &variable);
	void getVariable(SMTVariable *variable);

	SMTString name();
	void setName(SMTString &name);

public:
	const SMTOperatorROIElementPrivate& operator = (const SMTOperatorROIElementPrivate &elem);

public:
	bool m_bMask;
	SMTVariable m_variable;
};

class __declspec(dllimport) SMTResourceRefPrivate
{
public:
	enum ResourceType
	{
		SMT_UNDEF,
		SMT_CAMERA = 10,
		SMT_CONTROLLER,
		SMT_CAMERA3D,
		SMT_TCPIP_CONNECTION = 30,
		SMT_SERIAL_CONNECTION,
		SMT_GPIO,
		SMT_MODBUS_CONNECTION,
		SMT_HTTP_CONNECTION,
		SMT_HID_CONNECTION,
		SMT_WINDOW = 50,
		SMT_CALIB_INFO = 70,
		SMT_PLC_PROTOCOL = 80,
		SMT_QUEUE = 100
	};

public:
	SMTResourceRefPrivate();
	~SMTResourceRefPrivate();

	ResourceType type();
	SMTString id();
	void setID(SMTString &id);
	SMTString name();
	void setName(SMTString &name);

	bool isValid();
	void setValid(bool state);

	bool isCamera();
	bool isController();
	bool isHttp();
	bool isSerial();
	bool isModbus();
	bool isHID();
	bool isTcpIP();
	bool isGPIO();
	bool isWindow();
	bool isCalibInfo();
	bool is3DCamera();
	bool isPlc();
	bool isQueue();

	void setCamera(SMTCamera* cam);
	void setController(SMTController* controller);
	void setHttp(SMTHttp* http);
	void setSerial(SMTSerialPort* serial);
	void setModbus(SMTModbus* modbus);
	void setHID(SMTUSBHID *hid);
	void setTcpIp(SMTTcpIp *tcp);
	void setGPIO(SMTDIO* gpio);
	void setWindow(SMTImageWnd* wnd);
	void setCalibInfo(SMTCalibInfo* info);
	void set3DCamera(SMTCamera3D* cam);
	void setPlcCom(SMTPlcCom* plc);
	void setQueue(SMTQueue* queue);

	SMTCamera* toCamera();
	SMTController* toController();
	SMTHttp* toHttp();
	SMTSerialPort* toSerial();
	SMTModbus* toModbus();
	SMTUSBHID* toHID();
	SMTTcpIp* toTcpIp();
	SMTDIO* toGPIO();
	SMTImageWnd* toWindow();
	SMTCalibInfo* toCalibInfo();
	SMTCamera3D* to3DCamera();
	SMTPlcCom* toPlcCom();
	SMTQueue* toQueue();

	void releaseResource();

public:
	const SMTResourceRefPrivate& operator = (const SMTResourceRefPrivate &rscRef);

public:
	void addRef();
	void decRef();

private:
	int m_ref;
	ResourceType m_type;
	void* m_ptr;
	SMTString m_id;
	SMTString m_name;
	QMutex m_mutex;
	bool m_bValid;
};

class __declspec(dllimport) SMTCalibInfoPrivate
{
public:
	enum CoordSystemType
	{
		IMAGE_2D,
		WORLD_2D,
		WORLD_3D
	};

public:
	SMTCalibInfoPrivate();
	SMTCalibInfoPrivate(const SMTCalibInfoPrivate &elem);
	~SMTCalibInfoPrivate();

public:
	void addImgSystem(const SMTString &name, CoordSystemType type);
	void deleteImgSystem(const SMTString &name);
	void clearImgSystem();
	void changeImgSystemName(const SMTString &nameOld, const SMTString &nameNew);

	void addWorldSystem(const SMTString &name, CoordSystemType type);
	void deleteWorldSystem(const SMTString &name);
	void clearWorldSystem();

	bool setMatrix(const SMTString &coord1, const SMTString &coord2, const SMTMatrix &matrix);
	void deleteMatrix(const SMTString &coord1, const SMTString &coord2);
	void clearMatrix();

	bool addRotationCenter(const SMTString &name, const SMTString &coord, const SMTVariant &pt);
	void deleteRotationCenter(const SMTString &name);
	void clearRotationCenter();
	void getRotationCenters(SMTStringArray *names, SMTStringArray *coord, SMTVariantArray *pts);
	int countRotationCenters();
	bool getRotationCenterByIndex(int index, SMTString *name, SMTString *coord, SMTVariant* pt);
	bool getRotationCenterByName(const SMTString &name, SMTString *coord, SMTVariant* pt);

public:
	bool getMatrix(const SMTString &coord1, const SMTString &coord2, SMTMatrix *matrix);
	void getImgSystems(SMTStringArray *names, SMTNumberArray *types);
	void getWorldSystems(SMTStringArray *names, SMTNumberArray *types);

public:
	SMTCalibInfoPrivate &operator = (const SMTCalibInfoPrivate &elem);

private:
	bool CalOrientMapPath(QMap<QStringList, SMTMatrix> &data,
		SMTStringArray all, SMTString start, SMTString end, SMTMatrix *matrix);
	bool CalculateMatrix(QMap<QStringList, SMTMatrix> &mapPathToMatrix, QList<int> &listPath, SMTStringArray &coords, SMTMatrix &matrix, SMTMatrix *matrixOut, QStringList key = QStringList());
	void testaskpath(SMTMatrix &tp, int lastid);
	void askpath(int firstid, QMap<int, int> &path);
	QMap<int, int> getminpath();
	long MultiMatrix(SMTMatrix &srcMatrix1, SMTMatrix &srcMatrix2, SMTMatrix *dstMatrix, QStringList key = QStringList());
	long Inverse(SMTMatrix &srcMatrix, SMTMatrix *dstMatrix);


private:
	SMTStringArray m_imgSysArr;
	SMTNumberArray m_imgSysTypeArr;

	SMTStringArray m_worldSysArr;
	SMTNumberArray m_worldSysTypeArr;

	QMap<QStringList, SMTMatrix> m_mapMatrix;

	//rotation center;
	SMTStringArray m_coords;
	SMTStringArray m_centerName;
	SMTVariantArray m_centerPoints;
	QMutex m_centerMutex;

private:
	QMap<int, int> minPath;
	SMTMatrix allmap;
	int* mark;

	int  startid;
	int  endid;
	int  maxNum;

	SMTMatrix result;
};


class __declspec(dllimport) SMTOperatorROIPrivate
{
public:
	SMTOperatorROIPrivate();
	SMTOperatorROIPrivate(const SMTOperatorROIPrivate &roi);
	~SMTOperatorROIPrivate();

	void setEnabled(bool bVal);
	bool enabled();

	void getSupportedTypes(SMTNumberArray *types);
	void setSupportedTypes(const SMTNumberArray &types);

	bool supportMultiROIs();
	void setSupportMultiROIs(bool bVal);

	bool getBaseAlignment(SMTROIAlignment *roiAlign);
	void setBaseAlignment(const SMTROIAlignment &roiAlign);

	bool getROIAlignReference(SMTVariable *variable);
	void setROIAlignReference(const SMTVariable &variable);

	void enableROIAlignment(bool bVal);
	bool ROIAlignmentEnabled();

	void setEnableMask(bool bVal);
	bool isMaskEnabled();

	void addElement(const SMTOperatorROIElement &elem);
	bool removeElement(int index);
	bool replaceElement(int index, const SMTOperatorROIElement &elem);
	bool insertElement(int index, const SMTOperatorROIElement &elem);
	void clearElements();
	bool getElement(int index, SMTOperatorROIElement *elem);
	int countElements();
	bool moveElement(int from, int to);

	bool composeROIElement(SMTShape *shape);
	bool composeMaskElemnt(SMTShape *shape);
	bool composeAllElement(SMTShape *shape);

	bool getROIShapes(SMTShapeArray *shapeArr);
	bool getMaskShapes(SMTShapeArray *shapeArr);

	bool alignShape(SMTShape &shape, SMTShapeArray &shapeTrans);

private:
	bool calculateFixedROI();
	bool calculateFixedMask();

public:
	const SMTOperatorROIPrivate& operator = (const SMTOperatorROIPrivate &roi);

public:
	QList<SMTOperatorROIElement> m_listElem;
	SMTNumberArray m_listSupportedTypes;
	bool m_bMultiROIs;
	SMTVariable m_variable;
	bool m_bEnabled;
	bool m_bEnableROIAlign;
	bool m_bEnableMask;
	SMTROIAlignment m_baseAlign;

	SMTShape m_mask;
	SMTShape m_roi;
	SMTShape m_roiAll;
};

class __declspec(dllimport) SMTVariablePrivate : public QObject
{
	Q_OBJECT

public:

	enum VariableType
	{
		VARIABLE_BOOL = 0,
		VARIABLE_NUMBER,
		VARIABLE_STRING,
		VARIABLE_POINT,
		VARIABLE_IMG,
		VARIABLE_SHAPE,
		VARIABLE_POINTCLOUD,
		VARIABLE_CONTOUR,
		VARIABLE_ROIALIGNMENT,
		VARIABLE_POSE2D,
		VARIABLE_MATRIX,
		VARIABLE_BUFFER,
		VARIABLE_CHAR,
		VARIABLE_POINT3D = 500,
		VARIABLE_VEC3D,
		VARIABLE_SHAPE3D,
		VARIABLE_POSE3D,
		VARIABLE_RANGEIMG,
		VARIABLE_CONTOUR3D,
		VARIABLE_ARR_BOOL = 1000,
		VARIABLE_ARR_NUMBER,
		VARIABLE_ARR_STRING,
		VARIABLE_ARR_POINT,
		VARIABLE_ARR_IMG,
		VARIABLE_ARR_RANGEIMG,
		VARIABLE_ARR_SHAPE,
		VARIABLE_ARR_POINTCLOUD,
		VARIABLE_ARR_CONTOUR,
		VARIABLE_ARR_MATRIX,
		VARIABLE_ARR_BUFFER,
		VARIABLE_ARR_POINT3D = 1500,
		VARIABLE_ARR_SHAPE3D,
		VARIABLE_ARR_VEC3D,
		VARIABLE_ARR_CONTOUR3D,
		VARIABLE_ARR_VARIANT = 1800,
		VARIABLE_UNDEF = 2000
	};

	enum EffectiveArea
	{
		Local_Area,
		Flow_Area,
		Global_Area,
	};

public:

	SMTVariablePrivate(VariableType type, const SMTString &name, const SMTString &description, SMTOperator* parent);
	SMTVariablePrivate(const SMTVariablePrivate &var);
	~SMTVariablePrivate();

public:
	bool setValue(const SMTVariant &val);
	bool getValue(SMTVariant &val);

	void setReadOnly(bool bVal);
	bool readOnly();

	void setUseReference(bool bVal);
	bool useReference();

	bool valid();
	void setValid(bool bVal);

	void setEnabled(bool bVal);
	bool enabled();

	void setInUse(bool bState);
	bool isInUse();

	void setEffectiveArea(EffectiveArea area);
	EffectiveArea effectiveArea();

	void setCoordLabel(const SMTString &strLabel);
	SMTString coordLabel();

	VariableType variableType() const;

	void setName(SMTString &name);
	SMTString name();

	void setGroupName(const SMTString &groupName);
	SMTString groupName();

	void setIsEnv(bool bEnv);
	bool isEnv();

	void setDescription(SMTString &description);
	SMTString description();

	SMTOperator* parent();

	bool addReference(SMTVariablePrivate *variable, const SMTRefFormat &format);
	void removeReference(SMTVariablePrivate* variable);
	void clearReference();
	int referenceCount();
	int indexOfReference(SMTVariablePrivate *variable, int from = 0);
	bool removeReferenceAt(int index);
	bool swapReference(int a, int b);
	bool replaceReference(int index, SMTVariablePrivate *variable, const SMTRefFormat &format);
	bool getReferenceInfo(int index, SMTVariable &variable, SMTRefFormat *format);

	void addRef();
	void decRef();

	void installEventHandler(SMTVariableEventHandler* eventHandler);

	void clearAllRelations();

signals:
	void valueChanged();
	void stateChanged();
	void removeReferenceSignal(int index);
	void nameChanged();
	void groupNameChanged();

	public slots:
	void changeValue(const SMTVariant &val);

public:
	SMTVariablePrivate &operator = (const SMTVariablePrivate &var);

private:
	bool getReferenceValue(SMTVariant &variant);

	bool getRefValString(SMTVariant &variant);
	bool getRefValString(SMTVariablePrivate *variable, SMTString &strFormat, SMTString &strVal);
	bool getRefValStringArr(SMTVariant &variant);

	bool getRefValBool(SMTVariant &variant);
	bool getRefValBool(SMTVariablePrivate *variable, SMTString &strFormat, SMTBool &bVal);
	bool getRefValBoolArr(SMTVariant &variant);

	bool getRefValNumber(SMTVariant &variant);
	bool getRefValNumber(SMTVariablePrivate *variable, SMTString &strFormat, SMTNumber &number);
	bool getRefValNumArr(SMTVariant &variant);

	bool getRefValPoint(SMTVariant &variant);
	bool getRefValPoint(SMTVariablePrivate *variable, SMTString &strFormat, SMTPoint &ptVal);
	bool getRefValPtArr(SMTVariant &variant);

	bool getRefValPoint3D(SMTVariant &variant);
	bool getRefValPoint3D(SMTVariablePrivate *variable, SMTString &strFormat, SMTPoint3D &ptVal);
	bool getRefValPt3dArr(SMTVariant &variant);

	bool getRefValImg(SMTVariant &variant);
	bool getRefValImgArr(SMTVariant &variant);

	bool getRefValShape(SMTVariant &variant);
	bool getRefValShapeArr(SMTVariant &variant);

	bool getRefValCont(SMTVariant &variant);
	bool getRefValContArr(SMTVariant &variant);

	bool getRefValBuffer(SMTVariant &variant);
	bool getRefValBuffer(SMTVariablePrivate *variable, SMTString &strFormat, SMTBuffer &buffer);
	bool getRefValBufferArray(SMTVariant &variant);

	bool transPoint3DToBuffer(SMTRefFormat::DataFormat format, SMTPoint3D &ptVal, SMTBuffer::SMTMemorySequence seq, SMTBuffer &buffer);
	bool transPointToBuffer(SMTRefFormat::DataFormat format, SMTPoint &ptVal, SMTBuffer::SMTMemorySequence seq, SMTBuffer &buffer);
	bool transNumberToBuffer(SMTRefFormat::DataFormat format, const SMTNumber &val, SMTBuffer::SMTMemorySequence memseq, SMTBuffer &buffer);

	bool getRefValVariantArr(SMTVariant &variant);

	void getRefStringArray(SMTString &strRef);

public:
	SMTVariant m_val;
	QReadWriteLock m_lock;

	bool m_bReadOnly;
	bool m_bUseRef;

	bool m_bIsEnv;
	bool m_bValid;

	bool m_bEnabled;
	bool m_bInUse;
	int m_ref;

	QMutex m_mutex;
	SMTOperator *m_pOprBase;

	SMTString m_name;
	SMTString m_description;
	SMTString m_groupName;

	QList<SMTVariablePrivate*> m_listVariable;
	SMTStringArray m_listFormat;
	SMTBoolArray m_listAsElement;

	SMTVariableEventHandler *m_pEventHandler;
	EffectiveArea m_area;

	SMTString m_coordLabel;

	QList<SMTVariablePrivate*> m_listVarRefer;//record vars refered this var
};

class __declspec(dllimport) SMTSettingPage : public QWidget
{
	Q_OBJECT

public:
    explicit SMTSettingPage(QWidget *parent = nullptr);
	virtual ~SMTSettingPage();

    SMTImageWnd *imageWnd() const;
    void setImageWnd(SMTImageWnd *imageWnd);

    SMTMessageLabel *messageLbl() const;
    void setMessageLbl(SMTMessageLabel *messageLbl);

	void setOperator(SMTOperator* opr);

	//provide available reference info of variables
	void setAvailableReference(SMTVariableArray &variables);

	//provide available resources for ref
	void setAvailableResource(SMTResourceRefArray &resources);

	void setRTUpdateEnabled(bool bState);
	bool isRTUpdateEnabled();

	void setStatus(bool bStatus);
	bool getStatus();

	virtual SMTString name() = 0;
	virtual void initGUI() = 0;
	virtual void updateGUI(){};

	bool isFullPage();
	void release();

signals:
	void statusChanged(bool status);
	void parameterValueChanged();
	void showSettingDlg(int iType);
	void buttonVisible(bool bVisible);
	void buttonEnabled(bool bEnable);

protected:
    SMTImageWnd*    m_imageWnd;
    SMTMessageLabel* m_messageLbl;
	SMTOperator* m_opr;
	SMTVariableArray m_availableRef;
	SMTResourceRefArray m_availableResources;
	bool m_bFullPage;
	bool m_bRTUpdate;

private:
	bool m_bStatus;
};

class __declspec(dllimport) SMTSignalUnit
{
public:
	enum ConnectionType
	{
		Synchronous,
		Asynchronous
	};

public:
	SMTSignalUnit();
	virtual ~SMTSignalUnit();

public:
	void setName(const QString &name);
	QString name();

	void setRefName(const QString &name);
	QString refName();

	void setDescription(const QString &description);
	QString description();

	void setID(const QString &id);
	QString id();

	void setEnabled(bool state);
	bool enabled();

	bool connect(SMTSlotUnit *slot, ConnectionType type);
	void disconnect(SMTSlotUnit *slot);
	void disconnectAll();

	void emitSignal(SMTVariantArray &paras);

private:
	QString m_name;
	QString m_description;
	QString m_id;
	bool m_enabled;
	QList<SMTSlotUnit*> m_listSlot;
	QList<ConnectionType> m_listConnectType;
};

class __declspec(dllexport) SMTSlotUnit
{
public:
	enum ConnectionType
	{
		Synchronous,
		Asynchronous
	};

public:
	SMTSlotUnit();
	virtual ~SMTSlotUnit();

public:
	virtual void func(ConnectionType type, SMTVariantArray &paras);
	void activateSlot(ConnectionType type, SMTVariantArray &paras);

	void setSlotID(const QString &id);
	QString slotId();

	bool connectBySignalID(const QString &id, ConnectionType type);
	bool connect(SMTSignalUnit *signal, ConnectionType type);
	void getSignalIDConnected(QStringList &listID, QList<ConnectionType> &listType);

public:
	void disconnect(SMTSignalUnit *signal);
	void disconnectAll();

private:
	QList<SMTSignalUnit*> m_listSignal;
	QString m_id;
	QList<ConnectionType> m_listType;
};

class __declspec(dllimport) SMTEventMgr
{
public:
	SMTEventMgr();
	~SMTEventMgr();

public:
	SMTEventMgrPrivate *mgrPrivate;
};

class __declspec(dllexport) SMTEventEmiterPrivate
{
	enum ConnectionType
	{
		Synchronous,
		Asynchronous
	};

public:
	SMTEventEmiterPrivate();
	~SMTEventEmiterPrivate();

public:
	void registerSignal(const QString &signalName, const QString &description, bool bEnabled);
	void unregisterSignal(const QString &signalName);
	void enableSignal(const QString &signalName, bool state);
	void getSignals(QStringList &listSignals, QStringList &listDescription, QStringList &listID, SMTBoolArray &listEnabled);
	void connect(QString &signalName, SMTSlotUnit *receiver, ConnectionType type);
	void emitSignal(const QString &signalName, SMTVariantArray &paras);
	void clear();
	bool hasEnabledSignal();
	void getEnabledSignals(QStringList &listSignals, QStringList &listDescription, QStringList &listID);

private:
	SMTSignalUnit* findUnitByName(const QString &name);

public:
	QList<SMTSignalUnit*> m_listSignals;
};

class __declspec(dllimport) SMTLogOperator : public QObject
{
	Q_OBJECT

public:
	enum MessageLevel
	{
		DEBUG,
		NORMAL,
		WARNNING,
		//ERROR,
		CRITICAL
	};

public:
	SMTLogOperator(QObject *parent = nullptr);
	~SMTLogOperator();

public:
	void setEnabled(bool bState);
	bool enabled();

	void enableThreadID(bool bState);
	bool threadIDEnabled();

	void enableTimeStamp(bool bState);
	bool timeStampEnabled();

	void setLevelOutputMask(const QMap<MessageLevel, bool> &mapLevelState);
	void getLevelOutputMask(QMap<MessageLevel, bool> &mapLevelState);

	void setClassOutputMask(const QMap<int, bool> &mapClassState);
	void getClassOutputMask(QMap<int, bool> &mapClassState);

	void enableLevelOutput(MessageLevel level, bool bState);
	bool isLevelOutputEnabled(MessageLevel level);

	void enableClassOutput(int indexClass, bool bState);
	bool isClassOutputEnabled(int indexClass);

	void writeInfo(int level, int indexClass, const QString &uniqueID, const QString &info);

signals:
	void createRecord(int level, QString info);

private:
	QString getLevelString(int level);
	QString getClassString(int indexClass);
	QString getTimeString();
	QString getThreadIDString();

private:
	bool m_bEnabled;
	bool m_bEnableTimeStamp;
	bool m_bEnableThreadID;
	QMap<MessageLevel, bool> m_mapLevelState;
	QMap<int, bool> m_mapClassState;
	QMutex m_mutex;
};

class __declspec(dllexport) SMTLogGeneratorPrivate
{
public:
	enum MessageLevel
	{
		DEBUG,
		NORMAL,
		WARNNING,
		//ERROR,
		CRITICAL
	};

public:
	SMTLogGeneratorPrivate();
	~SMTLogGeneratorPrivate();

	void writeInfo(int level, int indexClass, const QString &uniqueID, const QString &info);
	SMTLogOperator* getOperator();


	static SMTLogOperator g_logOperator;
};

class __declspec(dllimport) SMTOperatorPrivate : public QObject
{
	Q_OBJECT

public:
	SMTOperatorPrivate(QObject *parent = 0);
	~SMTOperatorPrivate();

public:
	void sendStart(){};
	void sendEnd(){};
	void sendException(long errorNo){};

signals:
	void operatorStart();
	void operatorEnd();
	void operatorException(long errorNo);
	void operatorHitBreak();
	void nameChanged();
	void secNameChanged();
};

class __declspec(dllimport) SMTSectionPrivate : public QObject
{
	Q_OBJECT

public:
	SMTSectionPrivate(QObject *parent = 0);
	~SMTSectionPrivate();

signals:
	void nameChanged();
};
